#include "VulkanRHI.h"
#include "../Utils/StringUtil.h"
#include "../Utils/LogUtil.h"
#include "../Core/MaggotApp.h"
#include <set>
#include "../Misc/Crc.h"
#include "RenderState.h"
#include "../Core/CoreGlobals.h"
#include "VulkanAdapter.h"

#define USE_KHR_RAY_QUERY 0


VKAPI_ATTR VkBool32 VKAPI_CALL VulkanUserCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* callbackData, void* userData)
{

	if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT) {
		// LOGV(L"VKDbg : [%d] [%s] %s", callbackData->messageIdNumber, UTF8_TO_TCHAR(callbackData->pMessageIdName), UTF8_TO_TCHAR(callbackData->pMessage));
	}
	else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT) {
		LOGI(L"[%d] [%s] %s", callbackData->messageIdNumber, UTF8_TO_TCHAR(callbackData->pMessageIdName), UTF8_TO_TCHAR(callbackData->pMessage));
	}
	else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
		LOGW(L"[%d] [%s] %s", callbackData->messageIdNumber, UTF8_TO_TCHAR(callbackData->pMessageIdName), UTF8_TO_TCHAR(callbackData->pMessage));
	}
	else if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) {
		if (callbackData->messageIdNumber != 0) // 0 error is loader_create_device_chain: Failed to find 'vkGetInstanceProcAddr' 
			LOGE(L"[%d] [%s] %s", callbackData->messageIdNumber, UTF8_TO_TCHAR(callbackData->pMessageIdName), UTF8_TO_TCHAR(callbackData->pMessage));
	}

	return VK_FALSE;
}

VulkanRHI::VulkanRHI()
{
	// mApiVersion = VK_API_VERSION_1_0;
	mApiVersion = VK_MAKE_VERSION(1, 2, 0);
	// mApiVersion = VK_API_VERSION_1_1;
	mEnableValidation = true;
	mValidationLayers.push_back("VK_LAYER_KHRONOS_validation");
	mDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);

#if RENDER_DOC 1
	// It is has to be add is you want to use debug marker
	// not support here ???
	// mDeviceExtensions.push_back(VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
#else
	// RenderDoc not support those extensions

#if USE_KHR_RAY_QUERY
	mDeviceExtensions.push_back(VK_KHR_RAY_QUERY_EXTENSION_NAME);
#endif

	// Ray tracing related extensions required by this sample
	mDeviceExtensions.push_back(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
	mDeviceExtensions.push_back(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);

	// Required by VK_KHR_acceleration_structure
	mDeviceExtensions.push_back(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
#endif

	// Required by VK_KHR_acceleration_structure
	mDeviceExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
	mDeviceExtensions.push_back(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);

	// Required for VK_KHR_ray_tracing_pipeline
	mDeviceExtensions.push_back(VK_KHR_SPIRV_1_4_EXTENSION_NAME);

	// Required by VK_KHR_spirv_1_4
	mDeviceExtensions.push_back(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);

	mPhysicalDevice = VK_NULL_HANDLE;
	mGraphicsFamily = 0;
	mPresentFamily = 0;
}

VulkanRHI::~VulkanRHI()
{

}

void VulkanRHI::Init()
{
	CreateInstance();

	SetupReportCallback();

	CreateSurface();

	SelectPhysicalDevice();

	CreateLogicalDevice();

	CreateUniversal();
}

void VulkanRHI::Exit()
{
	vkDestroyDevice(mLogicalDevice, nullptr);

	if (mEnableValidation)
	{
		DestroyReportCallback();
	}

	vkDestroySurfaceKHR(mInstance, mSurface, nullptr);
	vkDestroyInstance(mInstance, nullptr);
}

void VulkanRHI::CreateInstance()
{
	VkApplicationInfo applicationInfo{};
	applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
	applicationInfo.pApplicationName = "MaggotEngine";
	applicationInfo.pEngineName = "MaggotEngine";
	applicationInfo.engineVersion = 1;
	applicationInfo.apiVersion = mApiVersion;

	std::vector<const char*> instanceExtensions = { VK_KHR_SURFACE_EXTENSION_NAME };
	instanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);

	// Get extensions supported by the instance and store for later use
	uint32 extCount = 0;
	vkEnumerateInstanceExtensionProperties(nullptr, &extCount, nullptr);
	if (extCount > 0)
	{
		std::vector<VkExtensionProperties> extensions(extCount);
		if (vkEnumerateInstanceExtensionProperties(nullptr, &extCount, &extensions.front()) == VK_SUCCESS)
		{
			for (VkExtensionProperties extension : extensions)
			{
				LOGI(L"support Entensions %s", UTF8_TO_TCHAR(extension.extensionName));
				mSupportedInstanceExtensions.push_back(extension.extensionName);
			}
		}
	}

	// Enabled requested instance extensions
	if (mEnabledInstanceExtensions.size() > 0)
	{
		for (const char* enabledExtension : mEnabledInstanceExtensions)
		{
			// Output message if requested extension is not available
			if (std::find(mSupportedInstanceExtensions.begin(), mSupportedInstanceExtensions.end(), enabledExtension) == mSupportedInstanceExtensions.end())
			{
				LOGI(L"Enabled instance extension %s is not present at instance level", enabledExtension);
			}
			else {
				instanceExtensions.push_back(enabledExtension);
			}
		}
	}

	VkInstanceCreateInfo instanceCreateInfo{};
	instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
	instanceCreateInfo.pNext = NULL;
	instanceCreateInfo.pApplicationInfo = &applicationInfo;
	if (instanceExtensions.size() > 0)
	{
		if (mEnableValidation)
		{
			// 安卓綁定錯誤回調需要使用 VK_EXT_DEBUG_REPORT_EXTENSION_NAME , win32使用 VK_EXT_DEBUG_UTILS_EXTENSION_NAME
			instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
		}
		instanceCreateInfo.enabledExtensionCount = (uint32)instanceExtensions.size();
		instanceCreateInfo.ppEnabledExtensionNames = instanceExtensions.data();
	}

	// The VK_LAYER_KHRONOS_validation contains all current validation functionality.
	// Note that on Android this layer requires at least NDK r20
	if (mEnableValidation)
	{
		// Check if this layer is available at instance level
		uint32 instanceLayerCount;
		vkEnumerateInstanceLayerProperties(&instanceLayerCount, nullptr);
		LOGI(L"instanceLayerCount %d", instanceLayerCount);
		std::vector<VkLayerProperties> instanceLayerProperties(instanceLayerCount);
		vkEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayerProperties.data());
		bool validationLayerPresent = false;
		for (VkLayerProperties layer : instanceLayerProperties) {
			LOGI(L"validationLayerName %s", UTF8_TO_TCHAR(layer.layerName));
			for (auto& validationLayerName : mValidationLayers) {
				if (strcmp(layer.layerName, validationLayerName) == 0) {
					validationLayerPresent = true;
					break;
				}
			}
		}
		if (validationLayerPresent) {
			instanceCreateInfo.ppEnabledLayerNames = mValidationLayers.data();
			instanceCreateInfo.enabledLayerCount = static_cast<uint32>(mValidationLayers.size());
		}
		else {
			mEnableValidation = false;
			LOGI(L"Validation layer VK_LAYER_KHRONOS_validation not present, validation is disabled");
		}
	}
	VK_CHECK_RESULT(vkCreateInstance(&instanceCreateInfo, nullptr, &mInstance));
}

void VulkanRHI::SetupReportCallback()
{
	if (!mEnableValidation)
		return;

	PFN_vkCreateDebugUtilsMessengerEXT dbgCreateDebugUtilsMessenger = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(mInstance, "vkCreateDebugUtilsMessengerEXT");
	if (!dbgCreateDebugUtilsMessenger) {
		LOGI(L"GetInstanceProcAddr: Unable to find vkCreateDebugUtilsMessengerEXT function.");
		return;
	}

	VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo{};
	messengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
	messengerCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
	messengerCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
	messengerCreateInfo.pfnUserCallback = VulkanUserCallback;
	messengerCreateInfo.pNext = nullptr;
	messengerCreateInfo.flags = 0;

	VK_CHECK_RESULT(dbgCreateDebugUtilsMessenger(mInstance, &messengerCreateInfo, nullptr, &mDebugMessenger));
}

void VulkanRHI::DestroyReportCallback()
{
	PFN_vkDestroyDebugUtilsMessengerEXT dbgDestroyDebugUtilsMessenger = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(mInstance, "vkDestroyDebugUtilsMessengerEXT");
	if (!dbgDestroyDebugUtilsMessenger) {
		LOGI(L"GetInstanceProcAddr: Unable to find vkDestroyDebugUtilsMessengerEXT function.");
		return;
	}
	dbgDestroyDebugUtilsMessenger(mInstance, mDebugMessenger, NULL);
}

void VulkanRHI::CreateSurface()
{
	VkWin32SurfaceCreateInfoKHR surfaceCreateInfo{};
	surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
	surfaceCreateInfo.pNext = nullptr;
	surfaceCreateInfo.flags = 0;
	surfaceCreateInfo.hwnd = MaggotApp::Get().GetWindow().GetWindowId();
	VK_CHECK_RESULT(vkCreateWin32SurfaceKHR(mInstance, &surfaceCreateInfo, nullptr, &mSurface));
}

void VulkanRHI::SelectPhysicalDevice()
{
	uint32 gpuCount;

	VK_CHECK_RESULT(vkEnumeratePhysicalDevices(mInstance, &gpuCount, nullptr));

	assert(gpuCount > 0);
	std::vector<VkPhysicalDevice> physicalDevices(gpuCount);
	VK_CHECK_RESULT(vkEnumeratePhysicalDevices(mInstance, &gpuCount, physicalDevices.data()));

	for (const auto& device : physicalDevices)
	{
		uint32 queueFamilyCount = 0;
		vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);

		// VkQueueFamilyProperties结构包含有关队列系列的一些详细信息，包括支持操作的类型以及可基于该家庭创建的队列数量
		std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
		vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());

		int i = 0;
		bool hasGraphicsFamily = false;
		bool hasComputeFamily = false;
		bool hasTransferFamily = false;
		bool hasPresentFamily = false;
		for (const auto& queueFamily : queueFamilies) {
			// 需要找到至少一个队列家庭的支持 VK_QUEUE_GRAPHICS_BIT -- 指定此队列中的队列支持图形操作
			// 更多支持可以查询 https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VkQueueFlagBits.html
			if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
			{
				mGraphicsFamily = i;
				hasGraphicsFamily = true;
			}

			if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_COMPUTE_BIT)
			{
				mComputeFamily = i;
				hasComputeFamily = true;
			}

			if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_TRANSFER_BIT)
			{
				mTransferFamily = i;
				hasTransferFamily = true;
			}

			VkBool32 presentSupport = false;
			vkGetPhysicalDeviceSurfaceSupportKHR(device, i, mSurface, &presentSupport);
			if (presentSupport) {
				mPresentFamily = i;
				hasPresentFamily = true;
			}

			if (hasGraphicsFamily && hasComputeFamily && hasTransferFamily && hasPresentFamily) {
				break;
			}
			i++;
		}

		uint32 extensionCount;
		vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);

		// 可以查询到设备支持的所有扩展
		std::vector<VkExtensionProperties> availableExtensions(extensionCount);
		vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, availableExtensions.data());

		std::set<std::string> requiredExtensions(mDeviceExtensions.begin(), mDeviceExtensions.end());

		// 便利支持的扩展, 如果有匹配的就从 requiredExtensions 中移除, 只需要判断 requiredExtensions 是否为空就知道是否支持所有需要的扩展了
		for (const auto& extension : availableExtensions) {
			// LOGI(L"physicalDevice extension %s", extension.extensionName);
			requiredExtensions.erase(extension.extensionName);
		}

		if (hasGraphicsFamily && hasComputeFamily && hasTransferFamily && hasPresentFamily && requiredExtensions.empty()) {

			// LOGI(L"physicalDevice %d %d %d", deviceExtensions.size(), graphicsFamily, presentFamily);

			mPhysicalDevice = device;
			// 獲取鋸齒採樣等級
			VkPhysicalDeviceProperties physicalDeviceProperties;
			vkGetPhysicalDeviceProperties(mPhysicalDevice, &physicalDeviceProperties);
			VkSampleCountFlags sampleCounts = physicalDeviceProperties.limits.framebufferColorSampleCounts & physicalDeviceProperties.limits.framebufferDepthSampleCounts;
			mMsaaSamples = VK_SAMPLE_COUNT_1_BIT;
			if (sampleCounts & VK_SAMPLE_COUNT_2_BIT) { mMsaaSamples = VK_SAMPLE_COUNT_2_BIT; }
			if (sampleCounts & VK_SAMPLE_COUNT_4_BIT) { mMsaaSamples = VK_SAMPLE_COUNT_4_BIT; }
			if (sampleCounts & VK_SAMPLE_COUNT_8_BIT) { mMsaaSamples = VK_SAMPLE_COUNT_8_BIT; }
			if (sampleCounts & VK_SAMPLE_COUNT_16_BIT) { mMsaaSamples = VK_SAMPLE_COUNT_16_BIT; }
			if (sampleCounts & VK_SAMPLE_COUNT_32_BIT) { mMsaaSamples = VK_SAMPLE_COUNT_32_BIT; }
			if (sampleCounts & VK_SAMPLE_COUNT_64_BIT) { mMsaaSamples = VK_SAMPLE_COUNT_64_BIT; }
		}
		else
		{
			LOGE(L"Find match physicalDevice fail start");

			LOGI(L"graphic : %d    compute : %d    transfer : %d    present : %d", (uint32)hasGraphicsFamily, (uint32)hasComputeFamily, (uint32)hasTransferFamily, (uint32)hasPresentFamily);
			for (const auto& extension : requiredExtensions)
			{
				LOGI(L"Lack extentsion : %s", UTF8_TO_TCHAR(extension.c_str()));
			}

			LOGE(L"Find match physicalDevice fail ended");
		}
	}

	if (mPhysicalDevice == VK_NULL_HANDLE)
	{
		LOGE(L"Could not find match physicalDevices");
		assert(0);
	}

	// Save properties and features, you can use vkGetPhysicalDeviceProperties2 and vkGetPhysicalDeviceFeatures2 to get old versions data
	// vkGetPhysicalDeviceProperties(mPhysicalDevice, &mDeviceProperties10);
	// vkGetPhysicalDeviceFeatures(mPhysicalDevice, &mDeviceFeatures10);

	mDeviceProperties11 = {};
	mDeviceProperties11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;

	mDeviceProperties12 = {};
	mDeviceProperties12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES;
	mDeviceProperties12.driverID = VK_DRIVER_ID_NVIDIA_PROPRIETARY;
	mDeviceProperties12.supportedDepthResolveModes = VK_RESOLVE_MODE_MAX_BIT;
	mDeviceProperties12.supportedStencilResolveModes = VK_RESOLVE_MODE_MAX_BIT;

	mDeviceFeatures11 = {};
	mDeviceFeatures11.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;

	mDeviceFeatures12 = {};
	mDeviceFeatures12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;


	// Get ray tracing pipeline properties, which will be used later on in the sample
	// 使用vkGetPhysicalDeviceProperties2来查询 GPU 支持的光线追踪功能拓展值, 主要看 : 
	// 1 maxRayRecursionDepth, 最大递归深度：即从单个光线执行的嵌套光线追踪调用的数量。即是光线在递归路径追踪器中可以在场景中反弹的次数。出于性能目的，递归实际上应保持在最低限度，有利于循环公式。
	// 2 shaderGroupHandleSize, 着色器标头大小：在创建着色器绑定表（SBT）的时候时候需要用到
	mRayTracingPipelineProperties = {};
	mRayTracingPipelineProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR;


	// To build AccelerationStructure
	mAccelerationStructureFeatures = {};
	mAccelerationStructureFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR;
	mAccelerationStructureFeatures.accelerationStructure = VK_TRUE;
	mAccelerationStructureFeatures.accelerationStructureCaptureReplay = VK_TRUE;
	// To use vkCmdTraceRaysKHR
	mRayTracingPipelineFeatures = {};
	mRayTracingPipelineFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR;
	mRayTracingPipelineFeatures.rayTracingPipeline = VK_TRUE;
	// To use deviceAddress
	mBufferDeviceAddressFeatures = {};
	mBufferDeviceAddressFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_ADDRESS_FEATURES_EXT;
	mBufferDeviceAddressFeatures.bufferDeviceAddress = VK_TRUE;
	// To use descriptorIndexing, but it conflict with VkPhysicalDeviceVulkan12Features, so not add in
	mDescriptorIndexingFeatures = {};
	mDescriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES;
	mDescriptorIndexingFeatures.runtimeDescriptorArray = true;
	mDescriptorIndexingFeatures.descriptorBindingPartiallyBound = true;
	mDescriptorIndexingFeatures.shaderSampledImageArrayNonUniformIndexing = true;
	mDescriptorIndexingFeatures.shaderUniformBufferArrayNonUniformIndexing = true;
	mDescriptorIndexingFeatures.shaderStorageBufferArrayNonUniformIndexing = true;
	mDescriptorIndexingFeatures.descriptorBindingSampledImageUpdateAfterBind = true;
	// To use ray query
	mRayQueryFeatures = {};
	mRayQueryFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR;
	mRayQueryFeatures.rayQuery = VK_TRUE;



	mDeviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
	mDeviceProperties2.pNext = &mDeviceProperties11;
	mDeviceProperties11.pNext = &mDeviceProperties12;
	mDeviceProperties12.pNext = &mRayTracingPipelineProperties;

	vkGetPhysicalDeviceProperties2(mPhysicalDevice, &mDeviceProperties2);

	mDeviceProperties10 = mDeviceProperties2.properties;


	mDeviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
	mDeviceFeatures2.pNext = &mDeviceFeatures11;
	mDeviceFeatures11.pNext = &mDeviceFeatures12;
	mDeviceFeatures12.pNext = &mAccelerationStructureFeatures;
	mAccelerationStructureFeatures.pNext = &mRayTracingPipelineFeatures;
	mRayTracingPipelineFeatures.pNext = &mBufferDeviceAddressFeatures;
#if USE_KHR_RAY_QUERY
	mBufferDeviceAddressFeatures.pNext = &mRayQueryFeatures;
#endif

	vkGetPhysicalDeviceFeatures2(mPhysicalDevice, &mDeviceFeatures2);

	mDeviceFeatures10 = mDeviceFeatures2.features;

	mDeviceFeatures10.geometryShader = VK_TRUE;
	mDeviceFeatures10.samplerAnisotropy = VK_TRUE;
	mDeviceFeatures10.textureCompressionBC = VK_TRUE;
	mDeviceFeatures10.textureCompressionASTC_LDR = VK_TRUE;
	mDeviceFeatures10.textureCompressionETC2 = VK_TRUE;
}

void VulkanRHI::CreateLogicalDevice()
{
	// 图形与显示的队列都创建
	std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
	std::set<uint32> uniqueQueueFamilies = { mGraphicsFamily, mComputeFamily, mTransferFamily, mPresentFamily };

	// 优先级
	float queuePriority = 1.0f;
	for (uint32 queueFamily : uniqueQueueFamilies) {
		VkDeviceQueueCreateInfo queueCreateInfo{};
		queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
		queueCreateInfo.queueFamilyIndex = queueFamily;
		queueCreateInfo.queueCount = 1;
		queueCreateInfo.pQueuePriorities = &queuePriority;
		queueCreateInfos.push_back(queueCreateInfo);
	}

	// 开启贴图采样无向过滤
	// deviceFeatures.samplerAnisotropy = VK_TRUE;
	// deviceFeatures.sampleRateShading = VK_TRUE;

	VkDeviceCreateInfo deviceCreateInfo{};
	deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;

	deviceCreateInfo.queueCreateInfoCount = static_cast<uint32>(queueCreateInfos.size());
	deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();

	deviceCreateInfo.pEnabledFeatures = &mDeviceFeatures10;

	// 创建逻辑设备时要支持的扩展
	deviceCreateInfo.enabledExtensionCount = static_cast<uint32>(mDeviceExtensions.size());
	deviceCreateInfo.ppEnabledExtensionNames = mDeviceExtensions.data();

	// 验证层
	if (mEnableValidation) {
		deviceCreateInfo.enabledLayerCount = static_cast<uint32>(mValidationLayers.size());
		deviceCreateInfo.ppEnabledLayerNames = mValidationLayers.data();
	}
	else {
		deviceCreateInfo.enabledLayerCount = 0;
	}

	// Vulkan >= 1.1 uses pNext to enable features, and not pEnabledFeatures
	deviceCreateInfo.pEnabledFeatures = nullptr;
	// Set pNext to enable all the pNext features
	deviceCreateInfo.pNext = &mDeviceFeatures2;

	VK_CHECK_RESULT(vkCreateDevice(mPhysicalDevice, &deviceCreateInfo, nullptr, &mLogicalDevice));



	// 获取队列句柄, 在提交命令时使用
	vkGetDeviceQueue(mLogicalDevice, mGraphicsFamily, 0, &mGraphicsQueue);
	vkGetDeviceQueue(mLogicalDevice, mComputeFamily, 0, &mComputeQueue);
	vkGetDeviceQueue(mLogicalDevice, mTransferFamily, 0, &mTransferQueue);
	// 在显示时使用
	vkGetDeviceQueue(mLogicalDevice, mPresentFamily, 0, &mPresentQueue);

	// 查询有关可用类型的内存使用的信息, 在查找匹配的內存類型時使用
	vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &mMemoryProperties);
}

void VulkanRHI::CreateUniversal()
{
	// 獲取設備對於深度支持的格式
	VkFormatProperties formatProps;
	// Depth format needs to be VK_FORMAT_D24_UNORM_S8_UINT on Android (if available).
	vkGetPhysicalDeviceFormatProperties(mPhysicalDevice, VK_FORMAT_D24_UNORM_S8_UINT, &formatProps);
	if ((formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) ||
		(formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))
		mDepthFormat = VK_FORMAT_D24_UNORM_S8_UINT;
	else
		mDepthFormat = VK_FORMAT_D16_UNORM;

	VulkanAdapter::Init();
}

VkInstance VulkanRHI::GetInstance() const
{
	return mInstance;
}

VkPhysicalDevice VulkanRHI::GetPhysicalDevice() const
{
	return mPhysicalDevice;
}

VkDevice VulkanRHI::GetLogicalDevice() const
{
	return mLogicalDevice;
}

VkSurfaceKHR VulkanRHI::GetSurface() const
{
	return mSurface;
}

VkFormat VulkanRHI::GetDepthFormat() const
{
	return mDepthFormat;
}

VkSampleCountFlagBits VulkanRHI::GetMsaaSamples() const
{
	return mMsaaSamples;
}

VkPhysicalDeviceProperties VulkanRHI::GetDeviceProperties() const
{
	return mDeviceProperties10;
}

VkPhysicalDeviceFeatures VulkanRHI::GetDeviceFeatures() const
{
	return mDeviceFeatures10;
}

VkQueue VulkanRHI::GetQueue(VkQueueFlagBits queueFlags /*= VK_QUEUE_GRAPHICS_BIT*/) const
{
	switch (queueFlags)
	{
	case VK_QUEUE_GRAPHICS_BIT:
		return mGraphicsQueue;
		break;
	case VK_QUEUE_COMPUTE_BIT:
		return mComputeQueue;
		break;
	case VK_QUEUE_TRANSFER_BIT:
		return mTransferQueue;
		break;
	case VK_QUEUE_SPARSE_BINDING_BIT:
	case VK_QUEUE_PROTECTED_BIT:
	case VK_QUEUE_FLAG_BITS_MAX_ENUM:
	default:
		assert(0);
		break;
	}
	return mGraphicsQueue;
}

VkQueue VulkanRHI::GetPresentQueue() const
{
	return mPresentQueue;
}

uint32 VulkanRHI::GetQueueFamily(VkQueueFlagBits queueFlags /*= VK_QUEUE_GRAPHICS_BIT*/) const
{
	switch (queueFlags)
	{
	case VK_QUEUE_GRAPHICS_BIT:
		return mGraphicsFamily;
		break;
	case VK_QUEUE_COMPUTE_BIT:
		return mComputeFamily;
		break;
	case VK_QUEUE_TRANSFER_BIT:
		return mTransferFamily;
		break;
	case VK_QUEUE_SPARSE_BINDING_BIT:
	case VK_QUEUE_PROTECTED_BIT:
	case VK_QUEUE_FLAG_BITS_MAX_ENUM:
	default:
		assert(0);
		break;
	}
	return mGraphicsFamily;
}

uint32 VulkanRHI::GetPresentFamily() const
{
	return mPresentFamily;
}

VkPhysicalDeviceRayTracingPipelinePropertiesKHR VulkanRHI::GetRayTracingPipelineProperties() const
{
	return mRayTracingPipelineProperties;
}

VkPhysicalDeviceAccelerationStructureFeaturesKHR VulkanRHI::GetAccelerationStructureFeatures() const
{
	return mAccelerationStructureFeatures;
}

uint32 VulkanRHI::FindMemoryType(uint32 typeFilter, VkMemoryPropertyFlags properties)
{
	// 找到适合缓冲区本身的内存类型
	for (uint32 i = 0; i < mMemoryProperties.memoryTypeCount; i++) {
		// memoryTypes 只关心内存种类
		if ((typeFilter & (1 << i)) && (mMemoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
		{
			return i;
		}
	}
	assert(false);
	return 0;
}

void VulkanRHI::GuessAccessByLayout(VkAccessFlags& srcAccessMask, VkAccessFlags& dstAccessMask, VkImageLayout oldLayout, VkImageLayout newLayout)
{
	// Source layouts (old)
	// Source access mask controls actions that have to be finished on the old layout
	// before it will be transitioned to the new layout
	switch (oldLayout)
	{
	case VK_IMAGE_LAYOUT_UNDEFINED:
		// Image layout is undefined (or does not matter)
		// Only valid as initial layout
		// No flags required, listed only for completeness
		srcAccessMask = 0;
		break;

	case VK_IMAGE_LAYOUT_PREINITIALIZED:
		// Image is preinitialized
		// Only valid as initial layout for linear images, preserves memory contents
		// Make sure host writes have been finished
		srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
		break;

	case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
		// Image is a color attachment
		// Make sure any writes to the color buffer have been finished
		srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
		break;

	case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
		// Image is a depth/stencil attachment
		// Make sure any writes to the depth/stencil buffer have been finished
		srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
		break;

	case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
		// Image is a transfer source
		// Make sure any reads from the image have been finished
		srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
		break;

	case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
		// Image is a transfer destination
		// Make sure any writes to the image have been finished
		srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
		break;

	case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
		// Image is read by a shader
		// Make sure any shader reads from the image have been finished
		srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
		break;
	default:
		// Other source layouts aren't handled (yet)
		break;
	}

	// Target layouts (new)
	// Destination access mask controls the dependency for the new image layout
	switch (newLayout)
	{
	case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
		// Image will be used as a transfer destination
		// Make sure any writes to the image have been finished
		dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
		break;

	case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
		// Image will be used as a transfer source
		// Make sure any reads from the image have been finished
		dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
		break;

	case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
		// Image will be used as a color attachment
		// Make sure any writes to the color buffer have been finished
		dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
		break;

	case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
		// Image layout will be used as a depth/stencil attachment
		// Make sure any writes to depth/stencil buffer have been finished
		// barrier.dstAccessMask = barrier.dstAccessMask | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
		dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
		break;

	case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
		// Image will be read in a shader (sampler, input attachment)
		// Make sure any writes to the image have been finished
		if (srcAccessMask == 0)
		{
			srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
		}
		dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
		break;
	default:
		// Other source layouts aren't handled (yet)
		break;
	}
}

void VulkanRHI::CreateBuffer(VkBuffer& buffer, VkDeviceMemory& bufferMemory, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperty, VkSharingMode sharingMode, std::vector<VkQueueFlagBits> queueFamilys)
{
	VkBufferCreateInfo bufferCreateInfo{};
	bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
	bufferCreateInfo.size = size;
	bufferCreateInfo.usage = usage;
	bufferCreateInfo.sharingMode = sharingMode;

	std::vector<uint32> queueFamilyIndices;
	for (const auto& queueFamily : queueFamilys)
	{
		queueFamilyIndices.push_back(GetQueueFamily(queueFamily));
	}
	bufferCreateInfo.queueFamilyIndexCount = static_cast<uint32>(queueFamilyIndices.size());
	bufferCreateInfo.pQueueFamilyIndices = queueFamilyIndices.data();

	VK_CHECK_RESULT(vkCreateBuffer(GetLogicalDevice(), &bufferCreateInfo, nullptr, &buffer));

	VkMemoryRequirements memRequirements;
	vkGetBufferMemoryRequirements(GetLogicalDevice(), buffer, &memRequirements);

	VkMemoryAllocateInfo memoryAllocateInfo{};
	memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
	memoryAllocateInfo.allocationSize = memRequirements.size;

	memoryAllocateInfo.memoryTypeIndex = FindMemoryType(memRequirements.memoryTypeBits, memoryProperty);

	// If usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, need to add a VkMemoryAllocateFlagsInfo to pNext of VkMemoryAllocateInfo
	VkMemoryAllocateFlagsInfo memoryAllocateFlagsInfo{};
	if (usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT)
	{
		memoryAllocateFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO;
		memoryAllocateFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT;
		memoryAllocateInfo.pNext = &memoryAllocateFlagsInfo;
	}

	VK_CHECK_RESULT(vkAllocateMemory(GetLogicalDevice(), &memoryAllocateInfo, nullptr, &bufferMemory));

	vkBindBufferMemory(GetLogicalDevice(), buffer, bufferMemory, 0);
}

void VulkanRHI::CreateImage(VkImage& image, VkDeviceMemory& imageMemory, uint32 width, uint32 height, VkImageUsageFlags usage, VkFormat format /*= VK_FORMAT_R8G8B8A8_UNORM*/, uint32 mipLevels /*= 1*/, VkMemoryPropertyFlags memoryProperty /*= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT*/, VkSampleCountFlagBits samples /*= VK_SAMPLE_COUNT_1_BIT*/, VkImageType imageType /*= VK_IMAGE_TYPE_2D*/, VkImageLayout imageLayout /*= VK_IMAGE_LAYOUT_UNDEFINED*/, uint32 arrayLayers /*= 1*/, VkImageTiling tiling /*= VK_IMAGE_TILING_OPTIMAL*/, VkSharingMode sharingMode /*= VK_SHARING_MODE_EXCLUSIVE*/, std::vector<VkQueueFlagBits> queueFamilys /*= std::vector<VkQueueFlagBits>()*/)
{
	CreateImage(image, imageMemory, { width, height, 1 }, usage, format, mipLevels, memoryProperty, samples, imageType, imageLayout, arrayLayers, tiling, sharingMode, queueFamilys);
}

void VulkanRHI::CreateImage(VkImage& image, VkDeviceMemory& imageMemory, VkImageCreateFlags flags, VkExtent3D extent, VkImageUsageFlags usage, VkFormat format, uint32 mipLevels, VkMemoryPropertyFlags memoryProperty, VkSampleCountFlagBits samples, VkImageType imageType, VkImageLayout imageLayout, uint32 arrayLayers, VkImageTiling tiling, VkSharingMode sharingMode, std::vector<VkQueueFlagBits> queueFamilys)
{
	VkImageCreateInfo imageCreateInfo{};
	imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
	imageCreateInfo.flags = flags;
	imageCreateInfo.imageType = imageType;
	imageCreateInfo.format = format;
	imageCreateInfo.extent = extent;
	imageCreateInfo.mipLevels = mipLevels;
	imageCreateInfo.arrayLayers = arrayLayers;
	imageCreateInfo.samples = samples;
	imageCreateInfo.tiling = tiling;
	imageCreateInfo.usage = usage;
	imageCreateInfo.sharingMode = sharingMode;

	std::vector<uint32> queueFamilyIndices;
	for (const auto& queueFamily : queueFamilys)
	{
		queueFamilyIndices.push_back(GetQueueFamily(queueFamily));
	}
	imageCreateInfo.queueFamilyIndexCount = static_cast<uint32>(queueFamilyIndices.size());
	imageCreateInfo.pQueueFamilyIndices = queueFamilyIndices.data();

	// VK_IMAGE_LAYOUT_UNDEFINED：GPU无法使用，第一个过渡将丢弃纹素
	// VK_IMAGE_LAYOUT_PREINITIALIZED：GPU不可用，但第一个过渡将保留纹素
	imageCreateInfo.initialLayout = imageLayout;

	VK_CHECK_RESULT(vkCreateImage(GetLogicalDevice(), &imageCreateInfo, nullptr, &image));

	VkMemoryRequirements memoryRequirements;
	vkGetImageMemoryRequirements(GetLogicalDevice(), image, &memoryRequirements);

	VkMemoryAllocateInfo memoryAllocateInfo{};
	memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
	memoryAllocateInfo.allocationSize = memoryRequirements.size;
	memoryAllocateInfo.memoryTypeIndex = FindMemoryType(memoryRequirements.memoryTypeBits, memoryProperty);

	VK_CHECK_RESULT(vkAllocateMemory(GetLogicalDevice(), &memoryAllocateInfo, nullptr, &imageMemory));
	VK_CHECK_RESULT(vkBindImageMemory(GetLogicalDevice(), image, imageMemory, 0));
}

void VulkanRHI::CreateImage(VkImage& image, VkDeviceMemory& imageMemory, VkExtent3D extent, VkImageUsageFlags usage, VkFormat format /*= VK_FORMAT_R8G8B8A8_UNORM*/, uint32 mipLevels /*= 1*/, VkMemoryPropertyFlags memoryProperty /*= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT*/, VkSampleCountFlagBits samples /*= VK_SAMPLE_COUNT_1_BIT*/, VkImageType imageType /*= VK_IMAGE_TYPE_2D*/, VkImageLayout imageLayout /*= VK_IMAGE_LAYOUT_UNDEFINED*/, uint32 arrayLayers /*= 1*/, VkImageTiling tiling /*= VK_IMAGE_TILING_OPTIMAL*/, VkSharingMode sharingMode /*= VK_SHARING_MODE_EXCLUSIVE*/, std::vector<VkQueueFlagBits> queueFamilys /*= std::vector<VkQueueFlagBits>()*/)
{
	CreateImage(image, imageMemory, 0, extent, usage, format, mipLevels, memoryProperty, samples, imageType, imageLayout, arrayLayers, tiling, sharingMode, queueFamilys);
}

void VulkanRHI::CreateImageView(VkImageView& imageView, VkImage image, VkFormat format, VkImageViewType viewType, VkImageSubresourceRange subresourceRange, VkComponentMapping components)
{
	VkImageViewCreateInfo imageViewCreateInfo{};
	imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
	imageViewCreateInfo.image = image;
	imageViewCreateInfo.viewType = viewType;
	imageViewCreateInfo.format = format;
	imageViewCreateInfo.components = components;
	imageViewCreateInfo.subresourceRange = subresourceRange;

	VK_CHECK_RESULT(vkCreateImageView(GetLogicalDevice(), &imageViewCreateInfo, nullptr, &imageView));
}

void VulkanRHI::TransferLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkImageSubresourceRange subresourceRange, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkQueueFlagBits srcQueueFlag, VkQueueFlagBits dstQueueFlag)
{
	VkAccessFlags tempSrcAccessMask = 0;
	VkAccessFlags tempDstAccessMask = 0;
	GuessAccessByLayout(tempSrcAccessMask, tempDstAccessMask, oldLayout, newLayout);

	VkImageMemoryBarrier imageMemoryBarrier{};
	imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
	imageMemoryBarrier.srcAccessMask = srcAccessMask == VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM ? tempSrcAccessMask : srcAccessMask;
	imageMemoryBarrier.dstAccessMask = dstAccessMask == VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM ? tempDstAccessMask : dstAccessMask;
	imageMemoryBarrier.oldLayout = oldLayout;
	imageMemoryBarrier.newLayout = newLayout;
	imageMemoryBarrier.srcQueueFamilyIndex = srcQueueFlag == VK_QUEUE_FLAG_BITS_MAX_ENUM ? VK_QUEUE_FAMILY_IGNORED : GetQueueFamily(srcQueueFlag);
	imageMemoryBarrier.dstQueueFamilyIndex = dstQueueFlag == VK_QUEUE_FLAG_BITS_MAX_ENUM ? VK_QUEUE_FAMILY_IGNORED : GetQueueFamily(dstQueueFlag);
	imageMemoryBarrier.image = image;
	imageMemoryBarrier.subresourceRange = subresourceRange;

	vkCmdPipelineBarrier(
		commandBuffer,
		srcStageMask,
		dstStageMask,
		0,
		0, nullptr,
		0, nullptr,
		1, &imageMemoryBarrier
	);
}

void VulkanRHI::TransferLayout(VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkImageSubresourceRange subresourceRange, VkQueueFlagBits commandQueue, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkQueueFlagBits srcQueueFlag, VkQueueFlagBits dstQueueFlag)
{
	VkAccessFlags tempSrcAccessMask = 0;
	VkAccessFlags tempDstAccessMask = 0;
	GuessAccessByLayout(tempSrcAccessMask, tempDstAccessMask, oldLayout, newLayout);

	VkCommandBuffer commandBuffer = GRenderState->BeginSingleCommand(commandQueue);

	VkImageMemoryBarrier imageMemoryBarrier{};
	imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
	imageMemoryBarrier.srcAccessMask = srcAccessMask == VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM ? tempSrcAccessMask : srcAccessMask;
	imageMemoryBarrier.dstAccessMask = dstAccessMask == VK_IMAGE_ASPECT_FLAG_BITS_MAX_ENUM ? tempDstAccessMask : dstAccessMask;
	imageMemoryBarrier.oldLayout = oldLayout;
	imageMemoryBarrier.newLayout = newLayout;
	imageMemoryBarrier.srcQueueFamilyIndex = srcQueueFlag == VK_QUEUE_FLAG_BITS_MAX_ENUM ? VK_QUEUE_FAMILY_IGNORED : GetQueueFamily(srcQueueFlag);
	imageMemoryBarrier.dstQueueFamilyIndex = dstQueueFlag == VK_QUEUE_FLAG_BITS_MAX_ENUM ? VK_QUEUE_FAMILY_IGNORED : GetQueueFamily(dstQueueFlag);
	imageMemoryBarrier.image = image;
	imageMemoryBarrier.subresourceRange = subresourceRange;

	vkCmdPipelineBarrier(
		commandBuffer,
		srcStageMask,
		dstStageMask,
		0,
		0, nullptr,
		0, nullptr,
		1, &imageMemoryBarrier
	);

	GRenderState->FlushSingleCommand(commandBuffer);
}

void VulkanRHI::CopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer buffer, VkImage image, uint32 width, uint32 height, VkImageSubresourceLayers imageSubresource, VkDeviceSize bufferOffset, uint32 bufferRowLength, uint32 bufferImageHeight, VkOffset3D imageOffset, VkImageLayout dstImageLayout)
{
	CopyBufferToImage(commandBuffer, buffer, image, { width, height, 1 }, imageSubresource, bufferOffset, bufferRowLength, bufferImageHeight, imageOffset, dstImageLayout);
}

void VulkanRHI::CopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer buffer, VkImage image, VkExtent3D extent, VkImageSubresourceLayers imageSubresource, VkDeviceSize bufferOffset, uint32 bufferRowLength, uint32 bufferImageHeight, VkOffset3D imageOffset, VkImageLayout dstImageLayout)
{
	VkBufferImageCopy bufferImageCopy{};
	bufferImageCopy.bufferOffset = bufferOffset;
	bufferImageCopy.bufferRowLength = bufferRowLength;
	bufferImageCopy.bufferImageHeight = bufferImageHeight;
	bufferImageCopy.imageSubresource = imageSubresource;
	bufferImageCopy.imageOffset = imageOffset;
	bufferImageCopy.imageExtent = extent;

	vkCmdCopyBufferToImage(
		commandBuffer,
		buffer,
		image,
		dstImageLayout,
		1,
		&bufferImageCopy
	);
}

void VulkanRHI::CopyBufferToImage(VkBuffer buffer, VkImage image, uint32 width, uint32 height, VkImageSubresourceLayers imageSubresource, VkQueueFlagBits commandQueue, VkDeviceSize bufferOffset, uint32 bufferRowLength, uint32 bufferImageHeight, VkOffset3D imageOffset, VkImageLayout dstImageLayout)
{
	CopyBufferToImage(buffer, image, { width, height, 1 }, imageSubresource, commandQueue, bufferOffset, bufferRowLength, bufferImageHeight, imageOffset, dstImageLayout);
}

void VulkanRHI::CopyBufferToImage(VkBuffer buffer, VkImage image, VkExtent3D extent, VkImageSubresourceLayers imageSubresource, VkQueueFlagBits commandQueue, VkDeviceSize bufferOffset, uint32 bufferRowLength, uint32 bufferImageHeight, VkOffset3D imageOffset, VkImageLayout dstImageLayout)
{
	VkCommandBuffer commandBuffer = GRenderState->BeginSingleCommand(commandQueue);

	VkBufferImageCopy bufferImageCopy{};
	bufferImageCopy.bufferOffset = bufferOffset;
	bufferImageCopy.bufferRowLength = bufferRowLength;
	bufferImageCopy.bufferImageHeight = bufferImageHeight;
	bufferImageCopy.imageSubresource = imageSubresource;
	bufferImageCopy.imageOffset = imageOffset;
	bufferImageCopy.imageExtent = extent;

	vkCmdCopyBufferToImage(
		commandBuffer,
		buffer,
		image,
		dstImageLayout,
		1,
		&bufferImageCopy
	);

	GRenderState->FlushSingleCommand(commandBuffer);
}

void VulkanRHI::CopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage image, VkBuffer buffer, VkExtent3D extent, VkImageSubresourceLayers imageSubresource, VkDeviceSize bufferOffset, uint32 bufferRowLength, uint32 bufferImageHeight, VkOffset3D imageOffset, VkImageLayout srcImageLayout)
{
	VkBufferImageCopy bufferImageCopy{};
	bufferImageCopy.bufferOffset = bufferOffset;
	bufferImageCopy.bufferRowLength = bufferRowLength;
	bufferImageCopy.bufferImageHeight = bufferImageHeight;
	bufferImageCopy.imageSubresource = imageSubresource;
	bufferImageCopy.imageOffset = imageOffset;
	bufferImageCopy.imageExtent = extent;

	vkCmdCopyImageToBuffer(
		commandBuffer,
		image,
		srcImageLayout,
		buffer,
		1,
		&bufferImageCopy
	);
}

void VulkanRHI::CopyImageToBuffer(VkImage image, VkBuffer buffer, VkExtent3D extent, VkImageSubresourceLayers imageSubresource, VkQueueFlagBits commandQueue, VkDeviceSize bufferOffset, uint32 bufferRowLength, uint32 bufferImageHeight, VkOffset3D imageOffset, VkImageLayout srcImageLayout)
{
	VkCommandBuffer commandBuffer = GRenderState->BeginSingleCommand(commandQueue);

	VkBufferImageCopy bufferImageCopy{};
	bufferImageCopy.bufferOffset = bufferOffset;
	bufferImageCopy.bufferRowLength = bufferRowLength;
	bufferImageCopy.bufferImageHeight = bufferImageHeight;
	bufferImageCopy.imageSubresource = imageSubresource;
	bufferImageCopy.imageOffset = imageOffset;
	bufferImageCopy.imageExtent = extent;

	vkCmdCopyImageToBuffer(
		commandBuffer,
		image,
		srcImageLayout,
		buffer,
		1,
		&bufferImageCopy
	);

	GRenderState->FlushSingleCommand(commandBuffer);
}

void VulkanRHI::GenerateMipmaps2D(VkCommandBuffer commandBuffer, VkImage image, uint32 width, uint32 height, VkFormat format, uint32 mipLevels, uint32 arrayLayers, VkImageLayout oldLayout /*= VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL*/, VkImageLayout newLayout /*= VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL*/, VkAccessFlags dstAccessMask /*= VK_ACCESS_SHADER_READ_BIT*/, VkPipelineStageFlags dstStageMask /*= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT*/, VkImageAspectFlags aspectMask /*= VK_IMAGE_ASPECT_COLOR_BIT*/)
{
	assert(mipLevels > 1);
	assert(mipLevels <= static_cast<uint32>(std::floor(std::log2(glm::max<uint32>(width, height)))) + 1);

	// check format mimap support 
	VkFormatProperties formatProperties;
	vkGetPhysicalDeviceFormatProperties(GVulkanRHI->GetPhysicalDevice(), format, &formatProperties);
	assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);

	for (uint32 layer = 0; layer < arrayLayers; ++layer)
	{
		// turn the last mip and current layer to src, current layer is i
		VkImageMemoryBarrier imageMemoryBarrier{};
		imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
		imageMemoryBarrier.image = image;
		imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
		imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
		imageMemoryBarrier.subresourceRange.aspectMask = aspectMask;
		imageMemoryBarrier.subresourceRange.baseArrayLayer = layer;
		imageMemoryBarrier.subresourceRange.layerCount = 1;
		imageMemoryBarrier.subresourceRange.levelCount = 1;

		int32 mipWidth = static_cast<int32>(width);
		int32 mipHeight = static_cast<int32>(height);

		for (uint32 mip = 1; mip < mipLevels; ++mip)
		{
			// Turn the mipmap -1 and layer = i to src
			imageMemoryBarrier.subresourceRange.baseMipLevel = mip - 1;
			imageMemoryBarrier.oldLayout = oldLayout;
			imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
			imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
			imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;

			vkCmdPipelineBarrier(commandBuffer,
				VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
				0, nullptr,
				0, nullptr,
				1, &imageMemoryBarrier);


			VkImageBlit imageBlit{};
			// Src area
			imageBlit.srcOffsets[0] = { 0, 0, 0 };
			imageBlit.srcOffsets[1] = { mipWidth, mipHeight, 1 };
			// Src mip level mip - 1, layer is the same
			imageBlit.srcSubresource.aspectMask = aspectMask;
			imageBlit.srcSubresource.mipLevel = mip - 1;
			imageBlit.srcSubresource.baseArrayLayer = layer;
			imageBlit.srcSubresource.layerCount = 1;
			// Dst area 
			imageBlit.dstOffsets[0] = { 0, 0, 0 };
			imageBlit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 };
			// Dst mip level mip, layer is the same
			imageBlit.dstSubresource.aspectMask = aspectMask;
			imageBlit.dstSubresource.mipLevel = mip;
			imageBlit.dstSubresource.baseArrayLayer = layer;
			imageBlit.dstSubresource.layerCount = 1;
			// vkCmdBlitImage指令可以进行复制，缩放和过滤图像的操作, 多次调用这一指令来生成多个不同细化级别的纹理图像数据, 使用这一指令，需要我们为纹理图像添加作为数据来源和接收目的使用标记, 所以在createTextureImage的时候使用 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT 这两个标记
			vkCmdBlitImage(commandBuffer,
				image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
				image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
				1, &imageBlit,
				VK_FILTER_LINEAR);


			// Trun the layout back to SHADER_READ
			imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
			imageMemoryBarrier.newLayout = newLayout;
			imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
			imageMemoryBarrier.dstAccessMask = dstAccessMask;

			vkCmdPipelineBarrier(commandBuffer,
				VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0,
				0, nullptr,
				0, nullptr,
				1, &imageMemoryBarrier);

			// Clac new width and height
			if (mipWidth > 1) mipWidth /= 2;
			if (mipHeight > 1) mipHeight /= 2;
		}

		// Turn the last mip back to shader read
		imageMemoryBarrier.subresourceRange.baseMipLevel = mipLevels - 1;
		imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
		imageMemoryBarrier.newLayout = newLayout;
		imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
		imageMemoryBarrier.dstAccessMask = dstAccessMask;

		vkCmdPipelineBarrier(commandBuffer,
			VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0,
			0, nullptr,
			0, nullptr,
			1, &imageMemoryBarrier);
	}
}

void VulkanRHI::GenerateMipmaps2D(VkImage image, uint32 width, uint32 height, VkFormat format, uint32 mipLevels, uint32 arrayLayers, VkQueueFlagBits commandQueue /*= VK_QUEUE_GRAPHICS_BIT*/, VkImageLayout oldLayout /*= VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL*/, VkImageLayout newLayout /*= VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL*/, VkAccessFlags dstAccessMask /*= VK_ACCESS_SHADER_READ_BIT*/, VkPipelineStageFlags dstStageMask /*= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT*/, VkImageAspectFlags aspectMask /*= VK_IMAGE_ASPECT_COLOR_BIT*/)
{
	assert(mipLevels > 1);
	assert(mipLevels <= static_cast<uint32>(std::floor(std::log2(glm::max<uint32>(width, height)))) + 1);

	// check format mimap support 
	VkFormatProperties formatProperties;
	vkGetPhysicalDeviceFormatProperties(GVulkanRHI->GetPhysicalDevice(), format, &formatProperties);
	assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);

	VkCommandBuffer commandBuffer = GRenderState->BeginSingleCommand(commandQueue);

	for (uint32 layer = 0; layer < arrayLayers; ++layer)
	{
		// turn the last mip and current layer to src, current layer is i
		VkImageMemoryBarrier imageMemoryBarrier{};
		imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
		imageMemoryBarrier.image = image;
		imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
		imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
		imageMemoryBarrier.subresourceRange.aspectMask = aspectMask;
		imageMemoryBarrier.subresourceRange.baseArrayLayer = layer;
		imageMemoryBarrier.subresourceRange.layerCount = 1;
		imageMemoryBarrier.subresourceRange.levelCount = 1;

		int32 mipWidth = static_cast<int32>(width);
		int32 mipHeight = static_cast<int32>(height);

		for (uint32 mip = 1; mip < mipLevels; ++mip)
		{
			// Turn the mipmap -1 and layer = i to src
			imageMemoryBarrier.subresourceRange.baseMipLevel = mip - 1;
			imageMemoryBarrier.oldLayout = oldLayout;
			imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
			imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
			imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;

			vkCmdPipelineBarrier(commandBuffer,
				VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
				0, nullptr,
				0, nullptr,
				1, &imageMemoryBarrier);


			VkImageBlit imageBlit{};
			// Src area
			imageBlit.srcOffsets[0] = { 0, 0, 0 };
			imageBlit.srcOffsets[1] = { mipWidth, mipHeight, 1 };
			// Src mip level mip - 1, layer is the same
			imageBlit.srcSubresource.aspectMask = aspectMask;
			imageBlit.srcSubresource.mipLevel = mip - 1;
			imageBlit.srcSubresource.baseArrayLayer = layer;
			imageBlit.srcSubresource.layerCount = 1;
			// Dst area 
			imageBlit.dstOffsets[0] = { 0, 0, 0 };
			imageBlit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 };
			// Dst mip level mip, layer is the same
			imageBlit.dstSubresource.aspectMask = aspectMask;
			imageBlit.dstSubresource.mipLevel = mip;
			imageBlit.dstSubresource.baseArrayLayer = layer;
			imageBlit.dstSubresource.layerCount = 1;
			// vkCmdBlitImage指令可以进行复制，缩放和过滤图像的操作, 多次调用这一指令来生成多个不同细化级别的纹理图像数据, 使用这一指令，需要我们为纹理图像添加作为数据来源和接收目的使用标记, 所以在createTextureImage的时候使用 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT 这两个标记
			vkCmdBlitImage(commandBuffer,
				image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
				image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
				1, &imageBlit,
				VK_FILTER_LINEAR);


			// Trun the layout back to SHADER_READ
			imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
			imageMemoryBarrier.newLayout = newLayout;
			imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
			imageMemoryBarrier.dstAccessMask = dstAccessMask;

			vkCmdPipelineBarrier(commandBuffer,
				VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0,
				0, nullptr,
				0, nullptr,
				1, &imageMemoryBarrier);

			// Clac new width and height
			if (mipWidth > 1) mipWidth /= 2;
			if (mipHeight > 1) mipHeight /= 2;
		}

		// Turn the last mip back to shader read
		imageMemoryBarrier.subresourceRange.baseMipLevel = mipLevels - 1;
		imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
		imageMemoryBarrier.newLayout = newLayout;
		imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
		imageMemoryBarrier.dstAccessMask = dstAccessMask;

		vkCmdPipelineBarrier(commandBuffer,
			VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask, 0,
			0, nullptr,
			0, nullptr,
			1, &imageMemoryBarrier);
	}

	GRenderState->FlushSingleCommand(commandBuffer);
}

